#include "des.h"
#include "mac.h"

/**
 * @brief 异或计算
 *
 * @param pDataIn  - 源数据
 * @param pDest    - 目标异或数值
 * @param DataSize - 数据有效长度
 * @param pDataOut - 异或后的数据
 */
static void DataXor(const uint8_t *pDataIn, const uint8_t *pDest, uint16_t DataSize, uint8_t *pDataOut);

static void DataXor(const uint8_t *pDataIn, const uint8_t *pDest, uint16_t DataSize, uint8_t *pDataOut)
{
  if ((pDataIn != NULL) && (pDest != NULL) && (pDataOut != NULL))
  {
    if (DataSize != 0)
    {
      for (uint16_t i = 0; i < DataSize; i++)
      {
        pDataOut[i] = pDest[i] ^ pDataIn[i];
      }
    }
  }
}

void Ansi99xGetMac(const uint8_t *pDataIn, uint16_t DataSize, const uint8_t *pKeyIn, uint8_t *pMacData)
{
  uint16_t x = 0, n = 0, j = 0;
  uint8_t TmpData[512] = {0}, MacData[8] = {0}, XorValue[8] = {0};

  if ((pDataIn != NULL) && (pKeyIn != NULL) && (pMacData != NULL))
  {
    if ((DataSize > 0) && (DataSize <= 512))
    {
      memcpy(TmpData, pDataIn, DataSize);
      x = DataSize / 8;
      n = DataSize % 8;
      if (n != 0)
      {
        memset(&TmpData[x * 8 + n], 0, 8 - n);
        x += 1;
      }

      memset(MacData, 0, 8);
      for (uint8_t i = 0; i < x; i++)
      {
        DataXor(MacData, &TmpData[j], 8, XorValue);
        CalDesEncrypt(pKeyIn, XorValue, MacData);
        j += 8;
      }

      memcpy(pMacData, MacData, 4);
    }
  }
}

void PbocDesMac(const uint8_t *pDataIn, uint16_t DataSize, const uint8_t *pKeyIn, const uint8_t *pInitValue, uint8_t *pMacData)
{
  uint16_t x = 0, n = 0, j = 0;
  uint8_t TmpData[512] = {0}, MacData[8] = {0}, XorValue[8] = {0};

  if ((pDataIn != NULL) && (pKeyIn != NULL) && (pInitValue != NULL) && (pMacData != NULL))
  {
    if ((DataSize != 0) && (DataSize <= 512))
    {
      memcpy(TmpData, pDataIn, DataSize);
      x = DataSize / 8;
      n = DataSize % 8;
      if (n != 0)
      {
        memset(&TmpData[x * 8 + n], 0, 8 - n);
        TmpData[x * 8 + n] = 0x80;

        x = x + 1;
      }
      else
      {
        memset(&TmpData[x * 8], 0, 8);
        TmpData[x * 8] = 0x80;

        x = x + 1;
      }

      memcpy(MacData, pInitValue, 8);
      for (uint16_t i = 0; i < x; i++)
      {
        DataXor(MacData, &TmpData[j], 8, XorValue);
        CalDesEncrypt(pKeyIn, XorValue, MacData);

        j += 8;
      }

      memcpy(pMacData, MacData, 4);
    }
  }
}

void Pboc3DesMac(const uint8_t *pDataIn, uint16_t DataSize, const uint8_t *pKeyIn, const uint8_t *pInitValue, uint8_t *pMacData)
{
  uint16_t x = 0, n = 0;
  uint8_t KeyL[8] = {0}, KeyR[8] = {0};
  uint8_t TmpData[512] = {0}, MacData[8] = {0}, XorValue[8] = {0};

  if ((pDataIn != NULL) && (pKeyIn != NULL) && (pInitValue != NULL) && (pMacData != NULL))
  {
    if ((DataSize != 0) && (DataSize <= 512))
    {
      memcpy(KeyL, pKeyIn, 8);
      memcpy(KeyR, &pKeyIn[8], 8);

      memcpy(TmpData, pDataIn, DataSize);
      x = DataSize / 8;
      n = DataSize % 8;
      if (n != 0)
      {
        memset(&TmpData[x * 8 + n], 0, 8 - n);
        TmpData[x * 8 + n] = 0x80;
      }
      else
      {
        memset(&TmpData[x * 8], 0, 8);
        TmpData[x * 8] = 0x80;
      }

      memcpy(MacData, pInitValue, 8);
      DataXor(MacData, &TmpData[0], 8, XorValue);
      for (uint16_t i = 1; i < x + 1; i++)
      {
        CalDesEncrypt(KeyL, XorValue, MacData);
        DataXor(MacData, &TmpData[i * 8], 8, XorValue);
      }

      CalDesEncrypt(KeyL, XorValue, MacData);
      CalDesDecrypt(KeyR, MacData, XorValue);
      CalDesEncrypt(KeyL, XorValue, MacData);
      memcpy(pMacData, MacData, 4);
    }
  }
}
